/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sa4w.action;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.channels.FileChannel;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import org.apache.struts2.StrutsStatics;
import sa4w.interfaces.Response;
import sa4w.interfaces.Server;
import sa4w.sedna.ServerSedna;

/**
 *
 * @author Leonardo Oliveira Moreira
 * 
 * Action that implements the methods of access to the database server
 */
public class ServerAction extends ActionSupport {

    private InputStream inputStream;
    private String host;
    private String database;
    private String user;
    private String password;
    private String query;
    
    private java.io.File upload;
    private String uploadFileName;
    
    private String configurationServerPath;

    public String getConfigurationServerPath() {
        return configurationServerPath;
    }

    public void setConfigurationServerPath(String configurationServerPath) {
        this.configurationServerPath = configurationServerPath;
    }

    public File getUpload() {
        return upload;
    }

    public void setUpload(File upload) {
        this.upload = upload;
    }

    public String getUploadFileName() {
        return uploadFileName;
    }

    public void setUploadFileName(String uploadFileName) {
        this.uploadFileName = uploadFileName;
    }

    public String getQuery() {
        return query;
    }

    public void setQuery(String query) {
        this.query = query;
    }
    
    public String getDatabase() {
        return database;
    }

    public void setDatabase(String database) {
        this.database = database;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public InputStream getInputStream() {
        return inputStream;
    }

    public void setInputStream(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    public String connectServer() {
        String serverPath = getServerPath();
        if (serverPath == null) {
            String json = "{\"serverPath\":\"No configuration file\"}";
            setInputStream(new ByteArrayInputStream(json.getBytes()));
            return "json";
        }        
        Server server = new ServerSedna();
        Response response = server.connectServer(serverPath);
        String sb = response.toJSON();
        setInputStream(new ByteArrayInputStream(sb.toString().getBytes()));
        return "json";
    }
    
    public String disconnectServer() {
        String serverPath = getServerPath();
        if (serverPath == null) {
            String json = "{\"serverPath\":\"No configuration file\"}";
            setInputStream(new ByteArrayInputStream(json.getBytes()));
            return "json";
        }        
        Server server = new ServerSedna();
        Map session = ActionContext.getContext().getSession();
        session.clear();
        Response response = server.disconnectServer(serverPath);
        String sb = response.toJSON();        
        setInputStream(new ByteArrayInputStream(sb.toString().getBytes()));
        return "json";
    }
    
    public String statusServer() {
        StringBuilder sb = new StringBuilder();
        Server server = new ServerSedna();
        boolean result = server.isServerConnected();
        sb.append("{");
        sb.append("\"reason\":\"" + result + "\"");
        if (result) {
            sb.append(",\"messages\":[{\"message\":\"Server is running\"}]");   
        }
        else {
            sb.append(",\"errorMessages\":[{\"errorMessage\":\"Server not is running\"}]");   
        }
        sb.append("}");
        setInputStream(new ByteArrayInputStream(sb.toString().getBytes()));
        return "json";        
    }
    
    public String startDatabase() {
        String serverPath = getServerPath();
        if (serverPath == null) {
            String json = "{\"serverPath\":\"No configuration file\"}";
            setInputStream(new ByteArrayInputStream(json.getBytes()));
            return "json";
        }          
        Server server = new ServerSedna();
        Response response = server.startDatabase(serverPath, database);
        response.addAditionalJson("\"database\":\"" + database + "\"");
        String sb = response.toJSON();
        setInputStream(new ByteArrayInputStream(sb.toString().getBytes()));
        return "json";
    }
    
    public String stopDatabase() {
        String serverPath = getServerPath();
        if (serverPath == null) {
            String json = "{\"serverPath\":\"No configuration file\"}";
            setInputStream(new ByteArrayInputStream(json.getBytes()));
            return "json";
        }                 
        Server server = new ServerSedna();
        Response response = server.stopDatabase(serverPath, database);
        response.addAditionalJson("\"database\":\"" + database + "\"");
        String sb = response.toJSON();
        setInputStream(new ByteArrayInputStream(sb.toString().getBytes()));
        return "json";
    }
    
    public String connectDatabase() {
        StringBuilder sb = new StringBuilder();
        Server server = new ServerSedna();
        Map session = ActionContext.getContext().getSession();
        Object connection = null;
        if (! session.containsKey("db_" + database)) {
            connection = server.connectDatabase(host, database, user, password);
            session.put("db_" + database, connection);
        }
        else {
            connection = session.get("db_" + database);
        }
        sb.append("{");
        sb.append("\"reason\":\"" + (connection != null) + "\"");
        if (connection != null) {
            sb.append(",\"messages\":[{\"message\":\"Connected to " + database + "\"}]");   
        }
        else {
            sb.append(",\"errorMessages\":[{\"errorMessage\":\"Server or database is not started\"}]");   
        }
        sb.append("}");
        setInputStream(new ByteArrayInputStream(sb.toString().getBytes()));
        return "json";
    }    
    
    public String disconnectDatabase() {
        Server server = new ServerSedna();
        Map session = ActionContext.getContext().getSession();
        Object connection = (Object) session.get("db_" + database);
        Response response = server.disconnectDatabase(connection);
        if (response.isReason()) {
            session.remove("db_" + database);
        }
        String sb = response.toJSON();
        setInputStream(new ByteArrayInputStream(sb.toString().getBytes()));
        return "json";
    }        
    
    public String getDatabasesServer() {
        String serverPath = getServerPath();
        if (serverPath == null) {
            String json = "{\"serverPath\":\"No configuration file\"}";
            setInputStream(new ByteArrayInputStream(json.getBytes()));
            return "json";
        }                
        StringBuilder sb = new StringBuilder();
        Server server = new ServerSedna();        
        sb.append("{");        
        String[] dbs = server.getDatabases(serverPath);
        sb.append("\"databases\":[");    
        if (dbs != null)
            for (String db : dbs) {
                sb.append("{\"database\":\"" + db + "\"},");
            }
        if (sb.toString().endsWith(","))
            sb = new StringBuilder(sb.substring(0, sb.length() - 1));
        sb.append("]}");        
        setInputStream(new ByteArrayInputStream(sb.toString().getBytes()));
        return "json";                
    }

    public String getActiveDatabases() {
        String serverPath = getServerPath();
        if (serverPath == null) {
            String json = "{\"serverPath\":\"No configuration file\"}";
            setInputStream(new ByteArrayInputStream(json.getBytes()));
            return "json";
        }                      
        StringBuilder sb = new StringBuilder();
        Server server = new ServerSedna();
        sb.append("{");
        String[] dbs = server.getActiveDatabases(serverPath);
        sb.append("\"databases\":[");
        if (dbs != null)
            for (String db : dbs) {
                sb.append("{\"database\":\"" + db + "\"},");
            }
        if (sb.toString().endsWith(","))
            sb = new StringBuilder(sb.substring(0, sb.length() - 1));
        sb.append("]}");
        setInputStream(new ByteArrayInputStream(sb.toString().getBytes()));
        return "json";
    }
    
    public String executeQuery() {
        Server server = new ServerSedna();    
        Map session = ActionContext.getContext().getSession();
        Object connection = (Object) session.get("db_" + database);        
        String queryResult = null;
        try {
            queryResult = server.executeQuery(connection, query);
        } 
        catch (Exception ex) {
            queryResult = "<error_sa4w>" + ex.getMessage() + "</error_sa4w>";
        }
        if (queryResult == null || queryResult.length() == 0) {
            queryResult = "<error_sa4w>" + "No results" + "</error_sa4w>";
        }
        setInputStream(new ByteArrayInputStream(queryResult.getBytes()));
        return "xml";
    }
    
    public String createDatabase() {
        String serverPath = getServerPath();
        if (serverPath == null) {
            String json = "{\"serverPath\":\"No configuration file\"}";
            setInputStream(new ByteArrayInputStream(json.getBytes()));
            return "json";
        }                    
        Server server = new ServerSedna();
        Response response = server.createDatabase(serverPath, database);
        response.addAditionalJson("\"database\":\"" + database + "\"");
        String sb = response.toJSON();
        setInputStream(new ByteArrayInputStream(sb.toString().getBytes()));
        return "json";
    }
    
    public String dropDatabase() {
        String serverPath = getServerPath();
        if (serverPath == null) {
            String json = "{\"serverPath\":\"No configuration file\"}";
            setInputStream(new ByteArrayInputStream(json.getBytes()));
            return "json";
        }                  
        Server server = new ServerSedna();
        Response response = server.dropDatabase(serverPath, database);
        response.addAditionalJson("\"database\":\"" + database + "\"");
        String sb = response.toJSON();
        setInputStream(new ByteArrayInputStream(sb.toString().getBytes()));
        return "json";
    }    
    
    public String loadDocument() {
        Server server = new ServerSedna();
        Map session = ActionContext.getContext().getSession();
        Object connection = (Object) session.get("db_" + database);
        
        ServletContext servletContext = (ServletContext) ActionContext.getContext().get(StrutsStatics.SERVLET_CONTEXT);
        
        String path = servletContext.getRealPath("/");
        
        path = path + "temp" + File.separator;

        copyFile(upload, new File(path + uploadFileName));

        Response response = new Response();
        try {
            server.executeQuery(connection, "LOAD \"" + path + uploadFileName + "\" \"" + uploadFileName + "\"");
            response.setReason(true);
            response.addMessage("Success");
        } 
        catch (Exception ex) {
            response.setReason(false);
            response.addErrorMessage(ex.getMessage());
        }
        
        File tempFile = new File(path + uploadFileName);
        if (tempFile.exists())
            tempFile.delete();
        
        setInputStream(new ByteArrayInputStream(response.toJSON().getBytes()));
        return "text";
    }

    public String getDocuments() {
        StringBuilder sb = new StringBuilder();
        Server server = new ServerSedna();
        Map session = ActionContext.getContext().getSession();
        Object connection = (Object) session.get("db_" + database);
        sb.append("{");
        String[] docs = null;
        try {
            docs = server.getDocuments(connection, database);
        } catch (Exception ex) {
            docs = null;
        }
        sb.append("\"documents\":[");
        if (docs != null)
            for (String doc : docs) {
                sb.append("{\"document\":\"" + doc + "\"},");
            }
        if (sb.toString().endsWith(","))
            sb = new StringBuilder(sb.substring(0, sb.length() - 1));
        sb.append("]}");
        setInputStream(new ByteArrayInputStream(sb.toString().getBytes()));
        return "json";
    }
    
    public String saveConfiguration() {
        String serverPath = getServerPath();
        
        ServletContext servletContext = (ServletContext) ActionContext.getContext().get(StrutsStatics.SERVLET_CONTEXT);

        String path = servletContext.getRealPath("/");

        path = path + "config" + File.separator + "configuration.properties";
        
        Response response = new Response();
        
        if (serverPath != null) {
            File file = new File(path);
            if (file.exists())
                file.delete();
            try {
                file.createNewFile();
            } catch (IOException ex) {
                response.setReason(false);
                response.addErrorMessage(ex.getMessage());
            }
        }
        try {
            PrintWriter pw = new PrintWriter(new File(path));
            pw.print("server.path=" + configurationServerPath);
            pw.close();
            response.setReason(true);
            response.addMessage("Success");
        } catch (FileNotFoundException ex) {
            response.setReason(false);
            response.addErrorMessage(ex.getMessage());            
        }
        setInputStream(new ByteArrayInputStream(response.toJSON().getBytes()));
        return "json";
    }
    
    public String getServerPathJson() {
        String serverPath = getServerPath();
        String json = "";
        if (serverPath != null) {
            json = "{\"serverPath\":\"" + serverPath + "\"}";
        }
        else {
            json = "{\"serverPath\":\"\"}";
        }
        setInputStream(new ByteArrayInputStream(json.getBytes()));
        return "json";
    }

    private static void copyFile(File in, File out) {
        try {
            FileChannel sourceChannel = new FileInputStream(in).getChannel();
            FileChannel destinationChannel = new FileOutputStream(out).getChannel();
            sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel);
            sourceChannel.close();
            destinationChannel.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    
    private String getServerPath() {
        ServletContext servletContext = (ServletContext) ActionContext.getContext().get(StrutsStatics.SERVLET_CONTEXT);
        
        String path = servletContext.getRealPath("/");
        
        path = path + "config" + File.separator + "configuration.properties";
        
        File f = new File(path);
        if (! f.exists())
            return null;
        
        Properties properties = new Properties();
        String result = null;

        try {
            properties.load(new FileInputStream(path));
            result = properties.getProperty("server.path");
        } catch (IOException ex) {
            result = null;
        }
        
        return result;
    }
    
}